package org.ytor.core.sqlflow.executor;

import lombok.Data;
import lombok.EqualsAndHashCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ytor.common.classmeta.ClassMetadata;
import org.ytor.common.classmeta.MethodMetadata;
import org.ytor.common.classmeta.ParameterMetadata;
import org.ytor.common.exception.BaseException;
import org.ytor.common.util.Strs;
import org.ytor.common.util.cache.C;
import org.ytor.common.util.cache.ClassCache;
import org.ytor.common.util.convert.Converts;
import org.ytor.common.util.invoke.Reflects;

import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.*;

/**
 * created by yangtong on 2025/8/9 13:04:45
 * <br/>
 * SQL 查询结果集
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class DQLResult extends SqlResult {

    private static final Logger log = LoggerFactory.getLogger(DQLResult.class);
    /**
     * 查询结果集
     */
    private List<Map<String, Object>> rows;

    /**
     * 按顺序保存的列名称
     */
    private List<String> columnNames;

    /**
     * 列类型ID
     */
    private List<Integer> columnTypes;

    /**
     * 列类型名称
     */
    private List<String> columnTypeNames;

    /**
     * 记录总数
     */
    private int rowCount;

    /**
     * 解析查询结果集并产生 QueryResult 对象
     */
    public static DQLResult parseResultSet(ResultSet rs) {
        DQLResult result = new DQLResult();
        try {
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();

            List<String> columnNames = new ArrayList<>(columnCount);
            List<Integer> columnTypes = new ArrayList<>(columnCount);
            List<String> columnTypeNames = new ArrayList<>(columnCount);
            List<Map<String, Object>> rows = new ArrayList<>();

            // 列元数据
            for (int i = 1; i <= columnCount; i++) {
                columnNames.add(metaData.getColumnLabel(i));
                columnTypes.add(metaData.getColumnType(i));
                columnTypeNames.add(metaData.getColumnTypeName(i));
            }

            // 遍历行
            while (rs.next()) {
                Map<String, Object> row = new LinkedHashMap<>();
                for (int i = 1; i <= columnCount; i++) {
                    row.put(Strs.toUnderline(columnNames.get(i - 1)), rs.getObject(i));
                }
                rows.add(row);
            }

            result.setRows(rows);
            result.setColumnNames(columnNames);
            result.setColumnTypes(columnTypes);
            result.setColumnTypeNames(columnTypeNames);
            result.setRowCount(rows.size());

            return result;
        } catch (SQLException e) {
            throw new BaseException("解析查询结果集失败：", e);
        }
    }


    /**
     * 结果集转换成 Bean
     */
    public <T> List<T> toBeans(Class<T> targetClass) {
        // 查询结果集为空，直接返回
        if (rows.isEmpty()) {
            return Collections.emptyList();
        }
        if (targetClass.equals(Map.class)) {
            return (List<T>) rows;
        }
        try {
            /*
             * 缓存查询结果集的字段与实体类setter方法的映射关系
             */
            Map<String, SetterMapping> finalMethodMapper = genMethodMapper(targetClass);

            List<T> beans = new ArrayList<>();
            for (Map<String, Object> row : rows) {
                T bean = Reflects.newInstance(targetClass);
                for (String key : row.keySet()) {
                    Object colVal = row.get(key);
                    SetterMapping setterMapping = finalMethodMapper.get(key);
                    if (setterMapping == null) {
                        continue;
                    }

                    // 调用bean 的setter方法
                    MethodMetadata methodMetadata = setterMapping.method();
                    Class<?> parameterType = setterMapping.parameterType();
                    // 如果类型完全匹配，直接赋值
                    if (colVal != null && parameterType.isAssignableFrom(colVal.getClass())) {
                        try {
                            methodMetadata.invoke(bean, colVal);
                        } catch (Exception e) {
                            log.error(e.getMessage(), e);
                        }
                    }
                    // 否则进行类型转换
                    else {
                        try {
                            methodMetadata.invoke(bean, Converts.convert(colVal, parameterType));
                        } catch (Exception e) {
                            log.error("字段{}类型转换失败：{}", key, e.getMessage());
                        }
                    }
                }

                beans.add(bean);
            }
            return beans;
        } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
            throw new BaseException(e);
        }
    }

    public <T> T toBean(Class<T> targetClass) {
        List<T> beans = toBeans(targetClass);
        if (beans.isEmpty()) {
            return null;
        }
        if (beans.size() > 1) {
            throw new IllegalStateException("期待得到一条数据，实际得到了" + beans.size() + "条");
        }
        return beans.getFirst();
    }

    /**
     * 返回 SQL 查询结果集和setter方法的映射
     */
    private <T> Map<String, SetterMapping> genMethodMapper(Class<T> targetClass) {
        Map<Class<?>, Map<String, SetterMapping>> cacheMap = C.get(getSql());
        if (cacheMap != null) {
            Map<String, SetterMapping> setterMapping = cacheMap.get(targetClass);
            if (setterMapping != null) {
                return setterMapping;
            }
        }

        // 如果没有缓存，则直接产生映射数据
        ClassMetadata<T> classMetadata = ClassCache.get(targetClass);
        Map<String, SetterMapping> finalMethodMapper = new HashMap<>();

        classMetadata.getMethods(i -> {
            // 方法必须是public访问权限，并且参数只有一个的setter
            return i.getName().startsWith("set") && i.isPublic() && i.parameters().size() == 1;
        }).forEach(methodMeta -> {
            // 1.将setter 方法名称转为对应的数据库字段名称
            String fieldName = Strs.toUnderline(methodMeta.getName().substring(3));

            // 2.检查参数类型
            ParameterMetadata parameterMetadata = methodMeta.parameters().getFirst();
            Class<?> parameterType = parameterMetadata.getType();

            // 特殊处理ID，因为id字段类型被PersistenceModel的第二个泛型K限制，直接解析类型会得到Object
//            if ("id".equals(fieldName) && PersistenceModel.class.isAssignableFrom(targetClass)) {
//                parameterType = resolveKType(targetClass);
//            }

            // 添加映射
            finalMethodMapper.put(fieldName, new SetterMapping(methodMeta, parameterType, true));
        });

        if (cacheMap != null) {
            cacheMap.put(targetClass, finalMethodMapper);
        } else {
            cacheMap = new HashMap<>();
            cacheMap.put(targetClass, finalMethodMapper);
            C.put(getSql(), cacheMap);
        }

        return finalMethodMapper;
    }

    /**
     * 解析 PersistenceModel 的泛型 K 类型
     */
//    private Class<?> resolveKType(Class<?> targetClass) {
//        Type genericSuperclass = targetClass.getGenericSuperclass();
//        if (genericSuperclass instanceof ParameterizedType parameterizedType) {
//            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
//            if (actualTypeArguments.length >= 2) {
//                Type idType = actualTypeArguments[1]; // 第二个泛型参数是 K
//                if (idType instanceof Class) {
//                    return (Class<?>) idType;
//                }
//            }
//        }
//        return Object.class; // 默认返回 Object
//    }
}
